import time,re
from typing import Tuple, Union
import uiautomator2 as u2

try:
    from .model import *
except (ModuleNotFoundError,ImportError):
    import sys,os
    sys.path.append(os.path.abspath('.'))
    from core.model import *



class PhysicalKey:
    Home='home'
    Back='back'
    Menu='menu'
    VolumeUp='volume_up'
    VolumeDown='volume_down'
    Power='power'


class Device:

    def __init__(self,wifi=None) -> None:
        if not wifi:
            self.device=self.connect_device()
        else:
            self.device=self.connect_device_with_wifi(wifi)
        self.delay=1
        self.delayed=True
        

    @classmethod
    def connect_device(cls):
        return u2.connect()
    
    @classmethod
    def connect_device_with_wifi(cls,wifi:str):
        pattern=r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d{4,6}"
        if not re.match(pattern,wifi):
            raise Exception('Invalid ip:port formation!')
        
        return u2.connect_adb_wifi(wifi)
    
    def wait(self):
        if not self.delayed:
            return
        time.sleep(self.delay)
    
    def wait_node(self,**selector):
        return self.device(**selector).wait(timeout=5)
    
    def wait_node_with_text(self,text):
        if not self.device(textContains=text).wait(timeout=5):
            raise Exception('期待的元素没有出现：'+text)
    
    def screen_on(self):
        self.device.screen_on()
        self.wait()
    
    def screen_off(self):
        self.device.screen_off()
        self.wait()

    
    def get_current_app(self):
        raw_dict=self.device.app_current()
        return AppInfo(**raw_dict)

    def launch_app(self,package,activity=None,need_wait=True,stop_first=False):
        self.device.app_start(package,activity,need_wait,stop_first)
        self.wait()
        print('App start:',package,activity)
    
    def dump_node_tree(self,save_to=None):
        doc= self.device.dump_hierarchy()
        if save_to:
            with open(save_to,'w',encoding='utf8') as f:
                f.write(doc)
            print('Save node tree done!')
    
    def get_node_list(self,**selector)->list:
        nodes=self.device(**selector)
        return nodes
    
    def get_node_list_by_rid(self,rid):
        return self.device(resourceId=rid)
    
    def click_point(self,point:Tuple[float,float]):
        self.device.click(*point)
        self.wait()
    
    def click_node(self,**selector):
        node=self.device(**selector)
        if not node:
            raise Exception('Node not Found:',selector)
        node.click()
        self.wait()


    
    def click_node_by_rid(self,rid,wait_text=None):
        node=self.device(resourceId=rid)
        if not node:
            raise Exception('Node not found:',rid)
        node.click()
        if wait_text:
            self.wait_node_with_text(wait_text)
        else:
            self.wait()

    def double_click_node(self,**selector):
        node=self.device(**selector)
        if not node:
            raise Exception('Node not Found:',selector)
        point=node.center()
        self.device.double_click(*point)
        self.wait()
    
    def double_click_node_by_rid(self,rid):
        self.double_click_node(resourceId=rid)
    
    def check_node_exists(self,**selector):
        return self.device.exists(**selector)

    def check_node_exists_by_rid(self,rid):
        return self.device.exists(resourceId=rid)

    def input_text(self,text,searched=False):
        self.device.set_fastinput_ime(True)
        self.device.clear_text()
        self.device.send_keys(text)
        if searched:
            self.device.send_action('search')
        self.device.set_fastinput_ime(False)
        self.wait()
        
    
    def press_phsical_key(self,key:PhysicalKey):
        self.device.press(key)
        self.wait()
    
    def go_back(self):
        self.device.press(PhysicalKey.Back)
        self.wait()
    
    def scroll_vert_forward(self):
        self.device.swipe_ext(u2.Direction.FORWARD)
        self.wait()
    
    def scroll_vert_backward(self):
        self.device.swipe_ext(u2.Direction.BACKWARD)
        self.wait()


    def try_up_find_node(self,rid,max_retry=3):
        '''
        尝试寻找指定node，如果当前目录不存在，则返回上一层继续
        '''
        while max_retry>0:
            if self.check_node_exists_by_rid(rid):
                break
            max_retry-=1
            self.go_back()
        else:
            raise Exception('Can not found node:'+rid)
    
    def __call__(self, **selector) :
        return self.device(**selector)



if __name__ == '__main__':
    d=Device()
    print(d.get_current_app())
    d.dump_node_tree('tree.xml')
    # d.screen_on()
    # d.scroll_to_horizontal_edge('right',scorllable=True,resourceId="com.tencent.mm:id/f67")
    # d.click_node(resourceId='com.tencent.mm:id/dt5')
    # d.click_node(className="android.widget.TextView",text="微信运动")
    # f=d.check_node_exists(text='步数排行榜')
    # print(f)
    # d.click_node(text='步数排行榜')
    # count=d.device(descriptionStartsWith='赞').count
    # print(count)
    # i=10
    # while i:
    #     d.scroll_vert_forward()

    # print(d(textContains='每日签到').info)
    # print(d(textContains='微信运动').child())

 